package AttachmentService

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gfile"
	"os"
	"seawolf-admin-go/internal/request/AttachmentReq"
	"seawolf-admin-go/utility/response"
	"seawolf-admin-go/utility/tools"
	"time"
)

func UploadCheck(r *ghttp.Request) *response.JsonResponse {
	var parames *AttachmentReq.UploadCheck
	if err := r.Parse(&parames); err != nil {
		return response.FailByRequestMessage(r, "上传失败："+err.Error())
	}
	ctx := r.GetCtx()

	// 使用md5查询数据库，如果存在则返回已存在，否则返回不存在
	aModel, err := GetModelByMd5(ctx, parames.FileMd5)
	if err != nil {
		return response.FailByRequestMessage(r, "上传失败："+err.Error())
	}
	if aModel != nil {
		return response.JsonByAll(r, 21001, "文件已存在", aModel)
	}
	score, err := getMemWithScore(ctx, parames.FileMd5)
	if err != nil {
		return response.FailByRequestMessage(r, "上传失败："+err.Error())
	}
	if len(score) > 0 {
		return response.JsonByAll(r, 21003, "断点续传", score)
	}
	return response.JsonByAll(r, 21002, "文件不存在")
}

var attachmentCachePrefix = "attachment:"

// 获取分片信息
func getMemWithScore(ctx context.Context, fileMd5 string) (map[string]string, error) {
	doVar, err := g.Redis().Do(ctx, "ZRANGE", attachmentCachePrefix+fileMd5, 0, -1, "WITHSCORES")
	if err != nil {
		return nil, err
	}
	return doVar.MapStrStr(), nil
}

// 保存分片信息
func chunkAdd(ctx context.Context, chunkIndex int, fileMd5 string, pieceMd5 string) error {
	_, err := g.Redis().Do(ctx, "ZADD", attachmentCachePrefix+fileMd5, chunkIndex, pieceMd5)
	if err != nil {
		return err
	}
	return nil
}

func chunkIsFull(ctx context.Context, fileMd5 string, chunkTotal int) (bool, error) {
	doVar, err := g.Redis().Do(ctx, "ZCARD", attachmentCachePrefix+fileMd5)
	if err != nil {
		return false, err
	}
	if doVar.Int() == chunkTotal {
		return true, nil
	}
	return false, nil
}

func isMerging(ctx context.Context, fileMd5 string) (bool, error) {
	doVar, err := g.Redis().Do(ctx, "SISMEMBER", attachmentCachePrefix+"merging_list", fileMd5)
	if err != nil {
		return false, err
	}
	if doVar.Int() > 0 {
		return true, nil
	}
	return false, nil
}
func setMerging(ctx context.Context, fileMd5 string) error {
	_, err := g.Redis().Do(ctx, "SADD", attachmentCachePrefix+"merging_list", fileMd5)
	if err != nil {
		return err
	}
	return nil
}
func getChunkList(ctx context.Context, fileMd5 string) ([]string, error) {
	doVar, err := g.Redis().Do(ctx, "ZRANGE", attachmentCachePrefix+fileMd5, 0, -1)
	if err != nil {
		return nil, err
	}
	return doVar.Strings(), nil
}

// 删除合并信息
func deleteMerging(ctx context.Context, fileMd5 string) error {
	_, err := g.Redis().Do(ctx, "SREM", attachmentCachePrefix+"merging_list", fileMd5)
	if err != nil {
		return err
	}
	return nil
}
func clearSet(ctx context.Context, fileMd5 string) {
	g.Redis().Do(ctx, "DEL", attachmentCachePrefix+fileMd5)
}

func pieceSave(ctx context.Context, uploadChunkPath, pieceMd5 string, file *ghttp.UploadFile) (int64, error) {
	/*err := os.Mkdir(uploadChunkPath, os.ModePerm)
	if err != nil {
		return 0, err
	}*/
	filePath := fmt.Sprintf("%s%s", uploadChunkPath, pieceMd5)
	f, e := os.Stat(filePath)
	if os.IsExist(e) {
		fmt.Println("片段存在")
		return f.Size(), nil
	}
	file.Filename = pieceMd5
	// 保存分片
	_, err := file.Save(uploadChunkPath)
	if err != nil {
		return 0, err
	}
	return file.Size, nil
}
func mergeFile(ctx context.Context, fileMd5, uploadChunkPath, uploadPath, saveFileName string, lastModified int64) (string, error) {
	// 取出临时分片信息
	chunkList, err := getChunkList(ctx, fileMd5)
	if err != nil {
		return "", err
	}
	// 判断存储目录是否存在
	if !gfile.Exists(uploadPath) {
		err := os.MkdirAll(uploadPath, os.ModePerm)
		if err != nil {
			return "", err
		}
	}
	// 创建文件
	filePath := fmt.Sprintf("%s%s", uploadPath, saveFileName)
	// 删掉已存在的文件
	os.Remove(filePath)
	f, err := os.Create(filePath)
	if err != nil {
		fmt.Println("创建文件失败 ", filePath)
		return "", err
	}
	defer f.Close()
	// 遍历分片列表，写入文件
	for _, chunk := range chunkList {
		chunkPath := fmt.Sprintf("%s/%s", uploadChunkPath, chunk)
		chunkFile, err := os.Open(chunkPath)
		if err != nil {
			return "", err
		}
		defer chunkFile.Close()
		_, err = f.Write(gfile.GetBytes(chunkPath))
		if err != nil {
			return "", err
		}
	}
	os.Chtimes(filePath, time.Unix(0, lastModified*int64(time.Millisecond)), time.Unix(0, lastModified*int64(time.Millisecond)))
	//newFileMd5 := gmd5.MustEncrypt(f)
	newFileMd5, err := tools.FileMD5sum(filePath)
	if err != nil {
		return "", err
	}
	return newFileMd5, nil
}

func pieceClaer(ctx context.Context, fileMd5, uploadChunkPath string) {
	// 取出临时分片信息
	chunkList, err := getChunkList(ctx, fileMd5)
	if err != nil {
		return
	}
	// 遍历分片列表，删除分片
	for _, chunk := range chunkList {
		chunkPath := fmt.Sprintf("%s/%s", uploadChunkPath, chunk)
		os.Remove(chunkPath)
	}
	// 删除分片信息
	clearSet(ctx, fileMd5)
}
